CAC Sales Website — Owner's Manual

Everything you need to maintain, update, and deploy this site.


PART 1: THE MAP

What exists and where

SalesWebsite/
├── index.html              ← Home / Programme page
├── about/index.html        ← About Lovinia
├── pricing/index.html      ← Pricing table + flipbook ← NEW
├── faq/index.html          ← FAQ ← NEW
├── register/index.html     ← Registration + Stripe ← NEW
├── _data/trainer.json      ← Shared trainer data ← NEW
├── articles/               ← Articles (existing)
├── privacy-policy.html     ← Existing
├── assets/                 ← Images and static files
└── _site/                  ← Auto-generated. DO NOT EDIT.

Rule: Never edit anything inside _site/. It is overwritten every build.


PART 2: THE ONE THING YOU NEED TO KNOW

Every page has a CONFIG block at the top of the <script> section. It is clearly marked:

<!-- CONFIG BLOCK — EDIT THIS SECTION ONLY -->

You never need to touch the HTML below it. All updates go in the CONFIG block.


PART 3: HOW TO UPDATE THINGS

A. Change the event date

Open pricing/index.html and register/index.html. Find:

date: "May 5–6, 2025",
earlybird_deadline: "2025-04-05",

Change both values. The early bird countdown and pricing auto-update from these two fields.

Format for earlybird_deadline: Always YYYY-MM-DD. The system calculates 30 days automatically — you set the exact cutoff date, not "30 days before."


B. Add course schedule content (Day 1 & Day 2)

Open pricing/index.html. Find the schedule block in CONFIG:

schedule: {
  day1: {
    title: "Day One",
    subtitle: "Foundation & Framework",
    sessions: [
      { time:"9:00 – 10:30am", topic:"[ADD: Session title]", detail:"[ADD: description]" },
      { time:"10:30 – 10:45am", topic:"Morning Break", break:true },
      ...
    ]
  }
}

Replace the [ADD: ...] placeholders. Do not change the time values — those are fixed. Only change topic and detail.

For breaks: Keep break:true and only change the topic text if needed. Do not add detail to break rows.


C. Add real testimonials

Open pricing/index.html. Find:

testimonials: [
  { placeholder:true, quote:"", name:"", role:"" },
  ...
],

Replace with:

{ placeholder:false, quote:"The actual quote from the participant.", name:"First Last", role:"Job Title, Company" },

Set placeholder:false and fill in all three fields. The placeholder card disappears automatically.


D. Update trainer bio

Open _data/trainer.json. Edit the paragraphs array. This is the single source of truth — currently only used by the flipbook page. In a future session, we can wire about/index.html to read from this file too, replacing its SITE_CONFIG.


E. Add an announcement

Open pricing/index.html. Find:

announcements: [
  "Existing announcement here.",
],

Add a new line inside the array. Use <strong>text</strong> for bold. To remove an announcement, delete its line. To hide all announcements, set the array to [].


F. Add Stripe payment links

Open register/index.html. Find the stripe: block in CONFIG. Replace each "REPLACE_WITH_..." placeholder with the actual Stripe Payment Link URL.

You will have 12 links in total: 3 ticket types × 2 payment methods (card + FPX) × 2 pricing tiers (early bird + standard).

How to get Stripe Payment Links:

  1. Log in to stripe.com → Products → Payment Links
  2. Create a link for each price point
  3. For FPX: in Payment Link settings, under Payment Methods, enable FPX (Malaysian banks)
  4. Copy the URL (starts with https://buy.stripe.com/...)
  5. Paste into CONFIG

PART 4: HOW TO BUILD AND DEPLOY

First time setup (one-time)

cd ~/Documents/github/SalesWebsite
npm install

Preview locally

cd ~/Documents/github/SalesWebsite
npx eleventy --serve

Opens at http://localhost:8080. Saves automatically on file changes.

Deploy to Cloudflare

cd ~/Documents/github/SalesWebsite
npx eleventy && wrangler deploy

This builds the _site/ folder then pushes to Cloudflare Workers.

Push to GitHub (version control)

cd ~/Documents/github/SalesWebsite
git add -A
git commit -m "describe what you changed"
git push

Do this after every change. Habit, not optional.


PART 5: COPYING THE NEW FILES INTO YOUR PROJECT

Run these commands once to add the new pages:

# Copy new pages
cp -r ~/Desktop/SalesWebsite-build/pricing ~/Documents/github/SalesWebsite/
cp -r ~/Desktop/SalesWebsite-build/faq ~/Documents/github/SalesWebsite/
cp -r ~/Desktop/SalesWebsite-build/register ~/Documents/github/SalesWebsite/
cp -r ~/Desktop/SalesWebsite-build/_data ~/Documents/github/SalesWebsite/

# Fix the broken pricing link in index.html
sed -i '' 's|PRICING-PAGE-LINK-HERE|/pricing/|g' ~/Documents/github/SalesWebsite/index.html

Then verify Eleventy sees the new folders:

cd ~/Documents/github/SalesWebsite && npx eleventy --dryrun 2>&1 | grep -E "pricing|faq|register"

You should see three lines — one for each new page.


PART 6: CLOUDFLARE — WHAT IT IS AND WHAT YOU HAVE

What Cloudflare Workers is

Your site is hosted on Cloudflare Workers — not a traditional web server. Think of it as a very fast delivery network that runs your site from data centres closest to each visitor. Zero monthly cost on the free tier.

What you get free

This is more than enough for your current scale.

Setting up lead capture (Cloudflare Workers KV)

This is for the "Notify Me" form on the pricing page and the in-house enquiry form on the register page. Both currently send a POST request to https://YOUR-WORKER.workers.dev/.... You need to create a Worker to receive and store these.

Step-by-step:

  1. Log in to dash.cloudflare.com
  2. Go to Workers & Pages → Create Application → Create Worker
  3. Name it cac-leads
  4. Paste this code into the editor:
export default {
  async fetch(request, env) {
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'POST',
          'Access-Control-Allow-Headers': 'Content-Type',
        }
      });
    }
    if (request.method !== 'POST') {
      return new Response('Not found', { status: 404 });
    }
    const url = new URL(request.url);
    const body = await request.json();
    const key = `${url.pathname.replace('/','')}_${Date.now()}_${Math.random().toString(36).slice(2,7)}`;
    await env.LEADS.put(key, JSON.stringify(body));
    return new Response(JSON.stringify({ ok: true }), {
      headers: {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*',
      }
    });
  }
};
  1. Go to Settings → Bindings → KV Namespace Bindings
  2. Add binding: variable name LEADS, create a new namespace called cac-leads-kv
  3. Deploy
  4. Copy your worker URL (e.g. https://cac-leads.YOUR-SUBDOMAIN.workers.dev)
  5. In pricing/index.html and register/index.html, replace https://YOUR-WORKER.workers.dev with your actual worker URL

To read your leads:

wrangler kv:key list --namespace-id YOUR_KV_NAMESPACE_ID
wrangler kv:key get --namespace-id YOUR_KV_NAMESPACE_ID "key_name_here"

Or export all:

wrangler kv:key list --namespace-id YOUR_KV_NAMESPACE_ID > leads_keys.txt

Get your namespace ID from the Cloudflare dashboard → Workers & Pages → KV.


PART 7: YOUR TO-DO LIST (IN ORDER)

Before launch

When you have schedule content

When you have testimonials

When date changes

Ongoing


PART 8: LINKS BETWEEN PAGES — THE FULL MAP

From To How
index.html /pricing/ "Pricing Table" link in module section (now fixed)
pricing/index.html /register/ "Register Now" button
pricing/index.html /faq/ "FAQ" button
pricing/index.html /about/ Trainer flipbook page + event bar
faq/index.html /pricing/ Refund/guarantee policy links
faq/index.html /register/ "Register Now" CTA
register/index.html /pricing/ "Terms apply" link
register/index.html /faq/ "Payment FAQ" link
All pages / Logo and "Programme" nav link
All pages /about/ Event bar + footer
All pages /articles/ Event bar
All pages /privacy-policy/ Footer

PART 9: WHAT NOT TO TOUCH


PART 10: IF SOMETHING BREAKS

Page not showing after deploy:

npx eleventy --dryrun

Look for errors. Usually a missing file or malformed path.

Eleventy build fails:

npx eleventy 2>&1 | head -40

Read the first error. Usually a Liquid/Nunjucks syntax error in a template.

Wrangler deploy fails:

wrangler whoami

If not logged in: wrangler login

Local preview not updating: Stop the server (Ctrl+C), clear _site/:

rm -rf _site && npx eleventy --serve

End of manual. Version 1.0 — April 2026.


Session Log: cac-corporate-enquiry Debug (2026-04-26)

What was broken

Enquiry form at sales-training/enquiry stopped working after CRM was built.

Root causes found (in order)

  1. Wrong worker URL — form posted to cac-leads.../corporate-enquiry (lead capture worker). Should be cac-corporate-enquiry.clarityawarenesscoaching.workers.dev. Fixed in sales-training/enquiry/index.html.
  2. D1 binding named wrong — Cloudflare dashboard had binding named D1 instead of DB. Worker code uses env.DB. Fixed manually on dashboard (rename binding to DB).
  3. Wrong table — Worker was rewritten for CRM and tried to upsert into contacts table. Live contacts is a B2B company master (company_name, general_email, pic_name — not a person/lead table). Enquiry data belongs in enquiries table. Fixed in src/index.js.
  4. Wrong interactions columns — Worker used outcome and initiated_by which don't exist in live interactions table. Live schema has worker_event instead. Fixed.
  5. FK constraint on interactionsinteractions.contact_id has a foreign key on contacts(id). Enquiry row id is not a contacts id. Removed interactions insert entirely — enquiries table is the log for this worker.

Files changed

Live schema reference (claritysystems-db)


Next Build: New Rise Training Provider Enquiry Flow

What it is

Replicate the sales-training/enquiry workflow for the Training Provider (New Rise or equivalent). Subdomain: newrise.claritysystems.work/enquiry (or similar).

What changes from CAC flow

Item CAC (current) New Rise (next build)
Form branding CAC logo, colours TP company name/brand
Worker cac-corporate-enquiry newrise-corporate-enquiry
Proforma issuer Clarity Awareness Coaching TP details + billing
Trainer profile CAC trainer profile PDF Same or TP-specific version
Database claritysystems-db → enquiries New D1 OR new table in claritysystems-db OR Google Sheet
Email sender [email protected] TP email (TBC)
Telegram notify CAC Telegram Same or new channel (TBC)

Confirmed requirements

  1. Enquiry form — TP branding replacing CAC brand
  2. Duplicate worker newrise-corporate-enquiry — TP details in proforma, payment, issued-by blocks
  3. Attachments — trainer profile, proforma invoice, tentative course schedule (TP billing details)
  4. Separate data store — new D1 database or Google Sheet for TP enquiries (decision pending)
  5. Confirmation flow — when client replies to confirm, send true invoice + confirmed schedule + trainer profile

Open decisions before build

What Lovinia needs to prepare

Session prompt for next build

Read BUILD_LOG.md and my work notes/OWNERS_MANUAL.md (New Rise section).

Task: Build the New Rise TP enquiry flow.

Stack: Same as CAC — Cloudflare Pages subdomain + new Worker + claritysystems-db (new table newrise_enquiries).

Start with:
1. Duplicate sales-training/enquiry/index.html → newrise/enquiry/index.html with TP branding
2. Duplicate workers/cac-corporate-enquiry → workers/newrise-corporate-enquiry with TP details
3. Add newrise_enquiries table to claritysystems-db
4. Wire subdomain newrise.claritysystems.work on Cloudflare Pages

TP details: [INSERT BEFORE SESSION]